package influx

import (
	"context"
	"fmt"
	"judge-service/configs"
	"log"
	"strings"
	"time"

	influxdb2 "github.com/influxdata/influxdb-client-go/v2"
	"github.com/pkg/errors"
)

type AggregateRes struct {
	Time  string  `json:"time,omitempty"`
	Value float64 `json:"value"`
}

var today = time.Now().Local().
	AddDate(0, 0, -1).
	Format("2006-01-02") + "T16:00:00Z" // 世界标准时间，加八个小时就是东八区时间的零点

var cstZone = time.FixedZone("CST", 8*3600) // 东八区

// Aggregate 聚合函数，可在一定时间间隔内求和、求最大、求最小、求平均
// aggType表示聚合类型，为sum、max、min、mean；
// metric是指标，为cpu_rate或mem_rate；；
// dimensions是维度；
// interval是时间间隔
func Aggregate(aggType, metric string, dimensions map[string]string, interval string) ([]AggregateRes, error) {
	switch aggType {
	case Sum, Max, Min, Mean:
	default:
		return nil, errors.New(fmt.Sprintf("The aggregation type [%s] is not supported for now", aggType))
	}

	client := influxdb2.NewClient(configs.GetConfig().InfluxUrl, configs.GetConfig().Token)
	defer client.Close()

	// 编写聚合脚本
	queryBuilder := strings.Builder{}
	queryBuilder.WriteString(fmt.Sprintf(`from(bucket: "%s")`, configs.GetConfig().Bucket))
	queryBuilder.WriteString(fmt.Sprintf(`|> range(start: %s)`, today))
	queryBuilder.WriteString(fmt.Sprintf(`|> filter(fn: (r) => r["_measurement"]== "%s")`, metric))
	queryBuilder.WriteString(`|> filter(fn: (r) => r["_field"]== "value")`)
	for k, v := range dimensions {
		queryBuilder.WriteString(fmt.Sprintf(`|> filter(fn: (r) => r["%s"]== "%s")`, k, v))
	}
	queryBuilder.WriteString(
		fmt.Sprintf(`|> aggregateWindow(every: %s, fn: %s, createEmpty: false)`,
			interval, aggType))

	// 执行聚合
	queryRes, err := client.QueryAPI(configs.GetConfig().Org).
		Query(context.Background(), queryBuilder.String())
	if err != nil {
		log.Printf("%v", err)
		return nil, errors.New("fail to query:" + err.Error())
	}
	aggRes := make([]AggregateRes, 0)
	for queryRes.Next() {
		aggRes = append(aggRes, AggregateRes{
			Time: queryRes.Record().Time().
				In(cstZone).Format("2006-01-02 15:04:05"),
			Value: queryRes.Record().Value().(float64),
		})
	}
	return aggRes, nil
}
